"""
pandas可以读取表格但是和想要的效果还是有很大差距
这个读取效果还不错，而且结果还是字典
满足大部分逻辑正常，代码清晰的表格，其它逻辑混乱的表格效果肯定不那么好
"""
from collections import namedtuple
import re

from utils import modify_list

TableGrid = namedtuple("TableGrid","text rowspan colspan unit")
unitPattren = re.compile(
    '(?<=[(\[（])[AµmMkKnpG]?[AVWsJΩF℃OH%]+[zZ]?(?=[)\]）])'
    )

class TableParser:

    def __init__(self) -> None:
        pass

    def __call__(self,table):
        head,bodys = self.parse_table(table)

        partInfoList = []

        for oneRow in bodys:
            partInfo = {}
            for hgrid,vgrid in zip(head,oneRow):
                if hgrid is None or vgrid is None:
                    partInfo["haveNone"] = 'None'
                    continue
                key = hgrid.text
                if not vgrid.text.endswith(hgrid.unit):
                    value = f"{vgrid.text} {hgrid.unit}"
                else:
                    value = vgrid.text
                if not vgrid.text:
                    value = ''
                partInfo[key] = value
            
            partInfoList.append(partInfo)
        return partInfoList


    def parse_table(self,table):
        ## 找出表头和表身
        theads = table.css('thead tr')
        if theads:
            tbodys = table.css('tbody tr')
        else:
            trs = table.css('tr')
            ## 分辨每一行是表头或者是表身
            ## 然后添加到对应的列表中去
            theads = []
            tbodys = []
            for tr in trs:
                if tr.css('th'):
                    theads.append(tr)
                else:
                    tbodys.append(tr)
        
        ## 从表头获取表的key
        headDistribute = self.expand_head(theads)

        ## 获取表身的数据
        bodyDistribute = self.expand_body(tbodys,len(headDistribute))
        
        return headDistribute,bodyDistribute

    def get_attr(self,tr,attr):
        ## 获得表格中格子的colspan和rowspan
        rowspan = tr.css(f'::attr({attr})').get()
        if rowspan:
            rowspan = int(rowspan)
        else:
            rowspan = 1
        return rowspan
    
    def get_one_row_grids(self,row):
        ## 获取一行的表格的格子
        rowDistribute = []
        grids = row.xpath('th|td')
        
        for grid in grids:
            text = modify_list(grid,' ::text')
            text = ''.join(text)
            rowspan = self.get_attr(grid,'rowspan')
            colspan = self.get_attr(grid,'colspan')
            unit = unitPattren.findall(text)
            if unit:
                unit = unit[0]
            else:
                unit = ''
            rowDistribute.append(TableGrid(text,rowspan,colspan,unit)) 
        return rowDistribute

    def expand_head(self,theads):
        ## 展开表头，使表头为一行，与数据对应
        ## 从表头获取表的key
        ## 返回表头的列表，元素是格子信息
        headDistribute = []
        for tr in theads:
            rowDistribute = self.get_one_row_grids(tr)
            headDistribute.append(rowDistribute)

        while len(headDistribute)>1:
            newRow = []
            head2 = headDistribute[1]
            colCount = 0
            for th in headDistribute[0]:
                if th.rowspan > 1:
                    rowspan = th.rowspan - 1
                else:
                    rowspan = 1
                if th.colspan > 1:
                    for _ in range(th.colspan):
                        if colCount >= len(head2):
                            continue
                        text = th.text + head2[colCount].text
                        colspan = 1
                        if head2[colCount].unit:
                            unit = head2[colCount].unit
                        else:
                            unit = th.unit
                        newRow.append(TableGrid(text,rowspan,colspan,unit))
                        colCount += 1
                else:
                    newRow.append(TableGrid(th.text,rowspan,1,th.unit))
            headDistribute.pop(0)
            headDistribute[0] = newRow
        return headDistribute[0]
    
    def expand_body(self,tbodys,keyLen):
        ## 将表身数据展开为和表头对应的样子
        bodyDistribute = []
        for tr in tbodys:
            rowDistribute = self.get_one_row_grids(tr)
            bodyDistribute.append(rowDistribute)

        newBody = [[None] * keyLen for _ in range(len(bodyDistribute))]
        totalRow = len(tbodys)

        for row,oneRow in enumerate(bodyDistribute):
            for i in range(keyLen):
                if not newBody[row][i]:
                    col = i
                    break
            for grid in oneRow:
                colspan = grid.colspan
                rowspan = grid.rowspan
                if row == totalRow - 1:
                    rowspan = 1
                for i in range(colspan):
                    for j in range(rowspan):
                        while newBody[row+j][col+i]:
                            col += 1
                        newBody[row+j][col+i] = grid
                col += colspan
                            
        return newBody


if __name__ == "__main__":
    from parsel import Selector
    from spider import get_resp
    url = 'https://www.murata.com/zh-cn/products/inductor/lctrap_filter'
    resp = get_resp(url)
    selector = Selector(resp.text)
    table = selector.css('table.m-table_table')[0]
    parse_table = TableParser()
    #print(parse_table.parse_table(table))
    tableRows = parse_table(table)
    for row in tableRows:
        print(row)